package Encryption;

import java.security.MessageDigest;
import java.util.Arrays;

import javax.crypto.Cipher; 
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;


public class AES_CBC {
	
	public byte[] encryptedText;
	public byte[] IV;
	
	private static String ALGO = "AES/CBC/PKCS5PADDING";
	private String keyValue = "EECE412IsAwesome";
	
	public void Encrypt(String plainText) throws Exception
	{
		final byte[] plainTextInByte = plainText.getBytes();
        
		Cipher c = Cipher.getInstance(ALGO);
		SecretKeySpec key = generateKey(keyValue);
		c.init(Cipher.ENCRYPT_MODE, key);
		
		encryptedText = c.doFinal(plainTextInByte);
		IV = c.getIV();		
	}
	
	public byte[] EncryptAndEncode(String plainText) throws Exception
	{
		final byte[] plainTextInByte = plainText.getBytes();
        
		Cipher c = Cipher.getInstance(ALGO);
		SecretKeySpec key = generateKey(keyValue);
		c.init(Cipher.ENCRYPT_MODE, key);
		
		encryptedText = c.doFinal(plainTextInByte);
		IV = c.getIV();		
		
		return EncodeEncIV();
	}
	
	public byte[] EncryptAndEncode(String plainText, String keyin) throws Exception
	{
		final byte[] plainTextInByte = plainText.getBytes();
		String newkeyvalue = keyValue + keyin;
        
		Cipher c = Cipher.getInstance(ALGO);
		SecretKeySpec key = generateKey(newkeyvalue);
		c.init(Cipher.ENCRYPT_MODE, key);
		
		encryptedText = c.doFinal(plainTextInByte);
		IV = c.getIV();		
		
		return EncodeEncIV();
	}
	
	private String Decrypt() throws Exception
	{
		Cipher c = Cipher.getInstance(ALGO);
		SecretKeySpec key = generateKey(keyValue);
		c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(IV));
		byte[] decrypted = c.doFinal(encryptedText);
		
		return new String(decrypted);
	}
	
	private String Decrypt(String keyin) throws Exception
	{
		String newkeyvalue = keyValue + keyin;
		
		Cipher c = Cipher.getInstance(ALGO);
		SecretKeySpec key = generateKey(newkeyvalue);
		c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(IV));
		byte[] decrypted = c.doFinal(encryptedText);
		
		return new String(decrypted);
	}
	
	public byte[] EncodeEncIV()
	{
	    final int IVlen = IV.length;
	    final int enclen = encryptedText.length;
	    
	    final byte[] result = new byte[IVlen + enclen];

		System.arraycopy(IV, 0, result, 0, IVlen);
		System.arraycopy(encryptedText, 0, result, IVlen, enclen);
		
		return result;

	}
	
	public String DecodeAndDecrypt(byte[] encodedByte) throws Exception
	{
		IV = Arrays.copyOfRange(encodedByte, 0, 16);
		encryptedText = Arrays.copyOfRange(encodedByte, 16, encodedByte.length);
		
	   //System.out.println("Ciphertext: " + Arrays.toString(ciphertext) + "\n");
	   //System.out.println("IV: " + Arrays.toString(cipherIV) + "\n");
		
		return Decrypt();
	}
	
	public String DecodeAndDecrypt(byte[] encodedByte, String keyin) throws Exception
	{
		IV = Arrays.copyOfRange(encodedByte, 0, 16);
		encryptedText = Arrays.copyOfRange(encodedByte, 16, encodedByte.length);
		
		return Decrypt(keyin);
	}
	
	private static SecretKeySpec generateKey(String keyValue) throws Exception
	{
		byte[] keyInByte = keyValue.getBytes();
		
		MessageDigest sha = MessageDigest.getInstance("SHA-1");
		keyInByte = sha.digest(keyInByte);
		keyInByte = Arrays.copyOf(keyInByte, 16); // use only first 128 bit
		
		SecretKeySpec key = new SecretKeySpec(keyInByte, "AES");

		return key;
	}
}
